﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using GraphSharp.Controls;
using XmlStudio.ViewModel;

namespace XmlStudio.Controls {
    /// <summary>
    /// Selection rectangle.
    /// </summary>
    public class RubberbandAdorner : Adorner {
        #region Member fields
        private Point? startPoint;
        private Point? endPoint;
        private Pen rubberbandPen;
        private DesignerCanvas designerCanvas;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the RubberbandAdorner class.
        /// </summary>
        /// <param name="designerCanvas">DesignerCanvas to set.</param>
        /// <param name="dragStartPoint">Dragging start point.</param>
        public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint)
            : base(designerCanvas) {
            if(designerCanvas == null)
                throw new ArgumentNullException("designerCanvas");

            this.designerCanvas = designerCanvas;
            this.startPoint = dragStartPoint;
            rubberbandPen = new Pen(Brushes.LightSlateGray, 1) { DashStyle = new DashStyle(new double[] { 2 }, 1) };
        }
        #endregion

        #region Event handlers
        /// <summary>
        /// Invoked on mouse move.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnMouseMove(MouseEventArgs e) {
            if(e.LeftButton == MouseButtonState.Pressed) {
                if(!this.IsMouseCaptured)
                    this.CaptureMouse();

                endPoint = e.GetPosition(this);
                UpdateSelection();
                this.InvalidateVisual();
            } else {
                if(this.IsMouseCaptured)
                    this.ReleaseMouseCapture();
            }

            e.Handled = true;
        }

        /// <summary>
        /// Invoked on mouse up.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnMouseUp(MouseButtonEventArgs e) {
            // release mouse capture
            if(this.IsMouseCaptured)
                this.ReleaseMouseCapture();

            // remove this adorner from adorner layer
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.designerCanvas);
            if(adornerLayer != null)
                adornerLayer.Remove(this);

            e.Handled = true;
        }

        /// <summary>
        /// Invoked on render.
        /// </summary>
        /// <param name="dc">The drawing instructions for a specific element. This context is provided to the layout system.</param>
        protected override void OnRender(DrawingContext dc) {
            base.OnRender(dc);

            // without a background the OnMouseMove event would not be fired!
            // Alternative: implement a Canvas as a child of this adorner, like
            // the ConnectionAdorner does.
            dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));

            if(this.startPoint.HasValue && this.endPoint.HasValue)
                dc.DrawRectangle(Brushes.Transparent, rubberbandPen, new Rect(this.startPoint.Value, this.endPoint.Value));
        }
        #endregion

        #region Methods
        /// <summary>
        /// Updates the selection.
        /// </summary>
        private void UpdateSelection() {
            designerCanvas.SelectionService.ClearSelection();

            if(startPoint != null) {
                if(endPoint != null) {
                    var rubberBand = new Rect(startPoint.Value, endPoint.Value);
                    foreach(var item in designerCanvas.Children) {
                        if(item is Border) {
                            var b = item as Border;
                            var layout = b.Child;
                            if(layout is XmlGraphLayout) {
                                var l = layout as XmlGraphLayout;
                                foreach(var vertex in l.Children) {
                                    if(vertex is VertexControl) {
                                        var vc = vertex as VertexControl;

                                        Rect itemRect = VisualTreeHelper.GetDescendantBounds(vc);
                                        Rect itemBounds = vc.TransformToAncestor(designerCanvas).TransformBounds(itemRect);

                                        if(rubberBand.Contains(itemBounds)) {
                                            designerCanvas.SelectionService.AddToSelection(vc);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        #endregion
    }
}
